#ifndef __QUEUE_H__
#define __QUEUE_H__

#include <vector>
#include "config.h"

using namespace std;

/* Optimizations:
 * -Use a single vector, manage separate vectors of indecies and change flags
 * -Use a list instead, but watch iterations
 */

struct QueueElement {
  int src; /* ID of requesting cache or  core.  This is used in priority matching */
  int L2src;
  unsigned long addr;
  unsigned long cyc;
  int delay;
  Cmd cmd;
  Block* blk;
};

class Queue{
public:
  Queue(int nmax_core=0, int nmin_core=0);

  bool Empty();
  /* Functions are in the order of a request's lifetime:
   * IQ (Input Queue) -> DQ (Decrement Queue) -> OQ (Output Queue) */

  /* IQ Functions */
  void NewReq(int nsrc, int naddr, int ndelay, int L2src, Cmd ncmd=R);
  void NewReq(QueueElement new_cmd);
  void Commit_Reqs(int n=1); /* Call at end of clock cycle.  Commits at most n requests. */

  /* DQ Functions */
  void Countdown(); /* Call at beginning of clock cycle */
  /* A committed request begins its delay.  If a command is requested but not committed,
   * the queue will not decrement its delay counter.  Requests are chosen to be
   * committed through a round robin rule depending on whic core requestsed it. 
   * The core ID should be stored in the "src" field of the request, and the core 
   * number should fall within the range of [min_core max_core] bound inclusive. */

  /* OQ is public for full functionality */
  vector<QueueElement> oq; /* Store output requests here. */ 

  /* AQ is public for full functionality */
  vector<QueueElement> aq;

  /* Other Function */
  int GetMinCore();
  int GetMaxCore();
  int GetModCore();
  int GetPriority();
private:
  int min_core;
  int max_core;
  int mod_core; /* number of cores */
  int newreq_delay;

  int priority;
  /* Store list of requests that need to be committed */
  vector<QueueElement> iq;
  /* Store decrementing requests here */
  vector<QueueElement> dq; 

  /* Get next new request from IQ, round robin from src */
  int GetNextNewReq();
  /* Calculates the priority distance for a given min/max and priority states */
  int PD(int p);
};

#endif
